/*
 * main.cpp
 *
 *  Created on: 24.12.2012
 *      Author: aska
 */
//  wine Hopper_EV2000_Boost_main.exe --help --hop_ser_name /dev/ttyUSB0 --hop_ser_baud 19200 --hop_addr 3 --todo a b c --use_dll
#include "main.h"

// Вспомогательная функция - выводит содержимое вектора строк.
void print_vector(const vector<string> &v, const string &name)
{
	cout << name << ": ";
	for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i)
		cout << "\t * " << *i << endl;
	cout << "\n";
}
// Функция уведомления, автоматически вызываемая при задании опции -v.
// В аргументе функции передается аргумент опции.
void notifier_ser_baud(int inp_arg)
{
	cout << "set serial baudrate: \t" << inp_arg << "\n";
	hopper_ser_baud = inp_arg;
}
/*void notifier_ser_name(string inp_arg)
{
	cout << "set_ser_name " << inp_arg << "\n";
	hopper_ser_name_str = inp_arg;
}*/

int main(int argc, char *argv[])
{
	use_dll = false;
	cout << "Start here" << endl;
	boost::program_options::options_description desc_visible("Visible options");
	desc_visible.add_options()
	    				("help", "produce help message")
	    				("hop_ser_baud", boost::program_options::value<int>( & hopper_ser_baud )->default_value( 9600 ), "set hopper serial baudrate")
	    				//("hop_ser_name", boost::program_options::value< vector<string> >(), "set serial name")
	    				("hop_ser_name", boost::program_options::value<string>( & hopper_ser_name_str )->default_value( "" ), "set hopper serial name")
	    				("hop_ser_No", boost::program_options::value<int>( & hopper_ser_No)->default_value( 0 ), "set No of serial port")
	    				("hop_addr", boost::program_options::value<int>( & hopper_addr )->default_value( 3 ), "set hopper address")
	    				("use_dll", boost::program_options::bool_switch( & use_dll )->default_value( false ), "use dll")
	    				("todo", boost::program_options::value< vector<string> >()->multitoken()->zero_tokens(),
	    						"todo list - (n) - command order\n"
	    						" hop_init - (1.1)\n"
	    						" hop_init_prep_mod - (2.1)\n"
	    						" hop_init_prep_mod_portNo - (2.1)\n"
	    						" hop_d2xx - (1.2)\n"
	    						" hop_open\n"
	    						" hop_open_d2xx\n"
	    						" hop_prep - (1.3)\n"
	    						" hop_simppo - (1.4 2.2) simple poll\n"
	    						" hop_test - (1.4 2.2) get test\n"
	    						" hop_status - (1.4 2.2) get status\n"
	    						" hop_put_coin - (1.4 2.2) put one coin\n"
	    						" hop_put_coins NCOINS - (1.4 2.2) set NCOINS to number of coins\n"
	    						" hop_finish - (1.5 2.3)"
	    						" readkey - wait for input");
	;
	// Группа опций, которую мы не будем показывать пользователю. Зачем эта группа, описано ниже.
	boost::program_options::options_description desc_hidden("Hidden options");
	desc_hidden.add_options()
        		// Опция с аргументом-списком. Обратите внимание на задание значения по умолчанию. Если
        		// для типа значения аргумента не определен оператор << для ostream, должно быть явно задано
        		// текстовое представление указываемого значения (в данном случае - пустого вектора).
        		("test",
        				boost::program_options::value< vector<string> >()->default_value(vector<string>(), ""),
        				"tests")
        				// Такая же опция.
        				("vec_str",
        						boost::program_options::value< vector<string> >()->default_value(vector<string>(), ""),
        						"debug vector of strings");
	boost::program_options::options_description desc;
    desc.add(desc_visible).add(desc_hidden);

    // Описание параметров ("позиционных опций"). Теперь внимание. В значение аргумента опции
    // pos2 попадают первые два параметра, остальные параметры попадают в значение аргумента
    // опции posrem (на это указывает -1).
    boost::program_options::positional_options_description pos_opt;
    pos_opt.add("pos2", 2).add("posrem", -1);

    boost::program_options::variables_map vm;
	try
	{
		// Предписываем использовать desc как множество распознаваемых опций и p как
		// множество "псевдоопций", предназначенных для "усыновления" параметров.
		boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(desc).positional(pos_opt).run(), vm);
		// Вызвать функции уведомления (value_notifier() в данном случае).
		boost::program_options::notify(vm);
	}
	catch (const boost::program_options::invalid_command_line_syntax &inv_syntax) {
		switch (inv_syntax.kind()) {
		case boost::program_options::invalid_syntax::missing_parameter:
			cout << "Missing argument for option '" << inv_syntax.tokens() << "'.\n";
			break;
		default:
			cout << "Syntax error, kind " << int(inv_syntax.kind()) << "\n";
			break;
		};
		return 1;
	}
	catch (const boost::program_options::unknown_option &unkn_opt) {
		cout << "Unknown option '" << unkn_opt.get_option_name() << "'\n";
		return 1;
	}
	// Задана опция help - выводим справку по опциям группы "Visible". Справка по опциям pos2 и
	// posrem не выводится (зачем пользователю знать, как мы обрабатываем параметры?).
	if (vm.count("help")) {
		cout << "help:" << endl << desc_visible << "\n";
		//cout << "todo:" << endl;
		//return 1;
	}
    // Типизация векторов.
	/*
    if (vm.count("hop_ser_name"))
    {

    	hopper_ser_name_str = * vm["hop_ser_name"].as< vector<string> >().begin();
    	cout << "set serial name: \t" << hopper_ser_name_str << endl;
    }*/
    if (vm.count("hop_ser_baud"))
    {

    	hopper_ser_baud = vm["hop_ser_baud"].as<int>();
    	cout << "set serial baudrate: \t" << hopper_ser_baud << endl;
    }
    if (vm.count("hop_addr"))
    {

    	hopper_addr = vm["hop_addr"].as<int>();
    	cout << "set hopper address: \t" << hopper_addr << endl;
    }

    if (vm.count("todo"))
    {
    	int ret_val = 0;
    	//cout << "todo" << endl;
    	cout << "ser name" << hopper_ser_name_str << endl;
    	cout << "baud" << hopper_ser_baud << endl;
    	cout << "addr" << hopper_addr << endl;
    	cout << "use dll" << use_dll << endl;
        print_vector(vm["todo"].as< vector<string> >(), "todo");
        //BOOST_FOREACH(string todo_action, vm["todo"].as< vector<string> >())
        vector<string> v = vm["todo"].as< vector<string> >();
    	for (vector<string>::const_iterator todo_action = v.begin(); todo_action != v.end(); ++todo_action)
    		//cout << "\t * " << *i << endl;
        {
        	cout << "action " << *todo_action << endl;
        	if (todo_action->compare("hop_init") == 0)
        	{
        		cout << " hopper init" << endl;
        		hopper_ev2000_inst = new hopper_ev2000_lib();
        		cout << "new hopper_ev2000_lib() ready" << endl;
        		ret_val = hopper_ev2000_inst->hopper_ev2000_dll_load();
        		cout << "hopper_ev2000_dll_load() " << ret_val << endl;
        		ret_val = hopper_ev2000_inst->hopper_init();
        		cout << "hopper_init() ready " << ret_val << endl;
        	}
        	if (todo_action->compare("hop_init_prep_mod") == 0)
        	{
        		cout << " hopper init-prepare-set_mode" << endl;
        		hopper_ev2000_inst = new hopper_ev2000_lib();
        		cout << "new hopper_ev2000_lib() ready" << endl;
        		ret_val = hopper_ev2000_inst->hopper_ev2000_dll_load();
        		cout << "hopper_ev2000_dll_load() " << ret_val << endl;
        		cout << " hopper open " << hopper_ser_name_str << endl;
        		char ser_name[32];
        		strcpy (ser_name, hopper_ser_name_str.c_str());
        		int mode = 2;
        		int inp_par = 2;
        		ret_val = hopper_ev2000_inst->hopper_init_prepare_mode_d2xx(2, 1, hopper_ser_No, ser_name);
        		cout << "hopper_init_prepare_mode_d2xx() ready " << ret_val << endl;
        	}
        	if (todo_action->compare("hop_init_prep_mod_portNo") == 0)
        	{
        		cout << " hopper init-prepare-set_mode-portNo" << endl;
        		hopper_ev2000_inst = new hopper_ev2000_lib();
        		cout << "new hopper_ev2000_lib() ready" << endl;
        		ret_val = hopper_ev2000_inst->hopper_ev2000_dll_load();
        		cout << "hopper_ev2000_dll_load() " << ret_val << endl;
        		cout << " hopper open " << hopper_ser_name_str << endl;
        		char ser_name[32];
        		strcpy (ser_name, hopper_ser_name_str.c_str());
        		int mode = 2;
        		int inp_par = 2;
        		ret_val = hopper_ev2000_inst->hopper_init_prepare_mode_d2xx_portNo(2, hopper_ser_No);
        		cout << "hopper_init_prepare_mode_d2xx_portNo() ready " << ret_val << endl;
        	}
       	if (todo_action->compare("hop_d2xx") == 0)
        	{
        		cout << " hopper set mode d2xx " << endl;
       			ret_val = hopper_ev2000_inst->hopper_set_mode(2);
        		cout << "hopper_set_mode(2)"<< ret_val << endl;
        	}
        	if (todo_action->compare("hop_open") == 0)
        	{
        		cout << " hopper open " << hopper_ser_name_str << endl;
        		char ser_name[32];
        		strcpy (ser_name, hopper_ser_name_str.c_str());
        		if (use_dll)
        			ret_val = hopper_ev2000_inst->hopper_port_open(ser_name);
        		else
        			ret_val = hopper_ev2000_inst->hopper_d2xx_open(ser_name);
        		cout << "hopper_port_open("<< ser_name << ")" << ret_val << endl;
        	}
        	if (todo_action->compare("hop_prep") == 0)
        	{
        		cout << " hopper prep" << endl;
        		char ser_name[32];
        		strcpy (ser_name, hopper_ser_name_str.c_str());
        		ret_val = hopper_ev2000_inst->hopper_prepare(ser_name);
        		cout << "hopper_prepare()" << ret_val << endl;
        	}
        	if (todo_action->compare("hop_simppo") == 0)
        	{
        		cout << " hopper simple poll" << endl;
        		//char ser_name[32];
        		//strcpy (ser_name, hopper_ser_name_str.c_str());
        		ret_val = hopper_ev2000_inst->hopper_send_simple_poll(hopper_addr);
        		cout << "hopper_send_simple_poll("<< hopper_addr << ")" << ret_val << endl;
        	}
        	if (todo_action->compare("hop_test") == 0)
        	{
        		cout << " hopper hop_test poll" << endl;
        		//char ser_name[32];
        		//strcpy (ser_name, hopper_ser_name_str.c_str());
        		char vp_hopper_registers[6];
        		ret_val = hopper_ev2000_inst->hopper_test_hopper(hopper_addr, vp_hopper_registers);
        		cout << "hopper_test_hopper("<< hopper_addr << ") " << ret_val << " : ";
        		for (int i1 = 0; i1 < 3; i1++)
        		{
        			//cout << " " << dec << (unsigned char)(vp_hopper_registers[i1]);
        			printf(" %2X", (unsigned char)(vp_hopper_registers[i1]));
        		}
        		cout << endl;
        		cout << "Absolute maximum current exceeded                  " <<  (((((vp_hopper_registers[1]) >> 0) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Payout timeout occurred                            " <<  (((((vp_hopper_registers[1]) >> 1) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Motor reversed during last payout to clear a jam   " <<  (((((vp_hopper_registers[1]) >> 2) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Opto fraud attempt, path blocked during idle       " <<  (((((vp_hopper_registers[1]) >> 3) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Opto fraud attempt, short-circuit during idle      " <<  (((((vp_hopper_registers[1]) >> 4) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Opto blocked permanently during payout             " <<  (((((vp_hopper_registers[1]) >> 5) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Power-up detected                                  " <<  (((((vp_hopper_registers[1]) >> 6) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Payout disabled                                    " <<  (((((vp_hopper_registers[1]) >> 7) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Opto fraud attempt, short-circuit during payout    " <<  (((((vp_hopper_registers[2]) >> 0) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Single coin payout mode                            " <<  (((((vp_hopper_registers[2]) >> 1) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Checksum A error                                   " <<  (((((vp_hopper_registers[2]) >> 2) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Checksum B error                                   " <<  (((((vp_hopper_registers[2]) >> 3) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Checksum C error                                   " <<  (((((vp_hopper_registers[2]) >> 4) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Checksum D error                                   " <<  (((((vp_hopper_registers[2]) >> 5) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Power fail during NV Memory write                  " <<  (((((vp_hopper_registers[2]) >> 6) & 0x01) == 0)?'0':'1') << endl;
        		cout << "Pin number mechanism enabled                       " <<  (((((vp_hopper_registers[2]) >> 7) & 0x01) == 0)?'0':'1') << endl;
        	}
        	if (todo_action->compare("hop_status") == 0)
        	{
        		char vp_byte_arr[9];
        		cout << " hopper status" << endl;
        		//char ser_name[32];
        		//strcpy (ser_name, hopper_ser_name_str.c_str());
        		ret_val = hopper_ev2000_inst->hopper_request_status(hopper_addr, vp_byte_arr);
        		cout << "hopper_request_status("<< hopper_addr << ") " << ret_val << endl;
         		for (int i1 = 0; i1 < 9; i1++)
				{
					//cout << hex << cout.width(2) << (unsigned char)(vp_byte_arr[i1]);
         			printf(" %2X", (unsigned char)(vp_byte_arr[i1]));
				}
         		cout << endl;
         		cout << "event counter             " << (unsigned int)vp_byte_arr[1] << endl;
         		cout << "payout coins remaining    " << (unsigned int)vp_byte_arr[2] << endl;
         		cout << "last payout: coins paid   " << (unsigned int)vp_byte_arr[3] << endl;
         		cout << "last payout: coins unpaid " << (unsigned int)vp_byte_arr[4] << endl;
        	}
        	if (todo_action->compare("hop_put_coin") == 0)
        	{
        		cout << " hopper put coin" << endl;
        		//char ser_name[32];
        		//strcpy (ser_name, hopper_ser_name_str.c_str());
        		int Coins_count = 1;
        		int Coins_rem = 0;
        		int Coins_paid = 0;
        		int Coins_unpaid = 0;
        		ret_val = hopper_ev2000_inst->hopper_put_coins_ack(hopper_addr, Coins_count,
        				&Coins_rem, &Coins_paid, &Coins_unpaid);
        		cout << "hopper_put_coins_ack("<< hopper_addr << ", " << Coins_count << "):" << ret_val << ", "
        				<< "Coins_rem: " << Coins_rem << "; "
        				<< "Coins_paid: " << Coins_paid << "; "
        				<< "Coins_unpaid: " << Coins_unpaid << ". "
        				<< endl;
        	}
        	if (todo_action->compare("hop_put_coins") == 0)
        	{
        		cout << " hopper put coins" << endl;
        		//char ser_name[32];
        		//strcpy (ser_name, hopper_ser_name_str.c_str());
        		todo_action++;
        		int Coins_count = 1;
        		Coins_count = atoi(todo_action->c_str());
        		int Coins_rem = 0;
        		int Coins_paid = 0;
        		int Coins_unpaid = 0;
        		ret_val = hopper_ev2000_inst->hopper_put_coins_ack(hopper_addr, Coins_count,
        				&Coins_rem, &Coins_paid, &Coins_unpaid);
        		cout << "hopper_put_coins_ack("<< hopper_addr << ", " << Coins_count << "):" << ret_val << ", "
        				<< "Coins_rem: " << Coins_rem << "; "
        				<< "Coins_paid: " << Coins_paid << "; "
        				<< "Coins_unpaid: " << Coins_unpaid << ". "
        				<< endl;
        	}
        	if (todo_action->compare("hop_finish") == 0)
        	{
        		cout << " hopper finish" << endl;
        		ret_val = hopper_ev2000_inst->hopper_close();
           		cout << "hopper_close()" << ret_val << endl;
       		//cout << "hopper_close" << endl;
        		hopper_ev2000_inst->dll_free();
        		//cout << "dll_free" << endl;
        		hopper_ev2000_inst->~hopper_ev2000_lib();
        	}
        	if (todo_action->compare("readkey") == 0)
        	{
        		char input_str[31];
        		cout << " type anything " << endl;
        		cin >> input_str;
        		cout << " done ";
        	}
       }
    }
	if (vm.count("use_dll")) {
		cout << "use_dll : \t\t\t" << "\n";
		//return 1;
	}
	cout << "Finish here" << endl;
	return 0;
}
